from django.shortcuts import render
from rest_framework.views import APIView
from rest_framework.response import Response
from django_redis import get_redis_connection
import pickle, base64
# Create your views here.
from carts.serializers import CartSerializer, SKUSerializer, CartDeleteSerializer, CartSelectionSerializer
from goods.models import SKU


class CartsView(APIView):

    # 预防验证用户,因为在post执行之前需要验证用户信息,所以需要跳过验证
    def perform_authentication(self, request):
        pass

    # 保存购物车数据
    def post(self, request):

        # 1.获取前端数据
        data = request.data

        # 2.验证
        ser = CartSerializer(data=data)
        # 直接抛出异常用rais_exception = True
        ser.is_valid(raise_exception=True)
        # 线下的时候腰查看异常错误
        # ser.is_valid()
        # print(ser.errors)
        # 获取验证之后的结果
        sku_id = ser.validated_data['sku_id']
        count = ser.validated_data['count']
        selected = ser.validated_data['selected']

        # 判断用户是否登陆
        try:
            user = request.user
        except:
            user = None

        if user is not None:
            # 用户已登陆
            # 1.建立缓存链接
            conn = get_redis_connection('cart')
            # 2.保存hash类型和集合类型
            # hash类型中的累加操作
            conn.hincrby('cart_%s' %user.id, sku_id, count)
            if selected:
                # 写入一个或多个数据
                conn.sadd('cart_selected_%s' % user.id, sku_id)
            # 3.返回结果
            return Response('ok')
        else:
            # 用户未登陆
            # 1.先判断之前是否登陆过(有cookie)
            cart_cookie = request.COOKIES.get('cart_cookie')
            if cart_cookie:
                # 解密
                cart = pickle.loads(base64.b64decode(cart_cookie))
            else:
                # 2.没有cookie先定义一个空字典
                cart = {}

            # 3.有cookie获取cookie累加
            sku_dict = cart.get(sku_id)
            if sku_dict:
                count += int(sku_dict.get('count'))

            cart[sku_id] = {
                'count': count,
                'selected': selected
            }
            # 4.将新的字典加入到cookie
            response = Response('ok')
            # 加密处理
            cart_cookie = base64.b64encode(pickle.dumps(cart)).decode()
            response.set_cookie('cart_cookie', cart_cookie, max_age=60*60*24)
            # 5.返回结果
            return Response('ok')

    # 获取购物车
    def get(self, request):

        # 判断用户是否登陆
        try:
            user = request.user
        except:
            user = None

        if user is not None:
            # 用户已登陆
            # 1.建立缓存链接
            conn = get_redis_connection('cart')
            # 2.获取hash类型和集合类型的数据
            # hash类型中的累加操作
            sku_id_count = conn.hgetall('cart_%s' % user.id)
            sku_selected = conn.smembers('cart_selected_%s' % user.id)
            # 转化为完整的购物车数据
            cart = {}
            for sku_id, count in sku_id_count.items():
                cart[int(sku_id)] = {
                    'count': int(count),
                    'selected': sku_id in sku_selected
                }
        else:
            # 用户未登陆
            # 1.先判断之前是否登陆过(有cookie)
            cart_cookie = request.COOKIES.get('cart_cookie')
            if cart_cookie:
                # 解密
                cart = pickle.loads(base64.b64decode(cart_cookie))
            else:
                # 2.没有cookie先定义一个空字典
                cart = {}

        # 查询商品对象
        skus = SKU.objects.filter(id__in=cart.keys())

        for sku in skus:
            sku.count = cart[sku.id]['count']
            sku.selected = cart[sku.id]['selected']

        ser = SKUSerializer(skus, many=True)
        return Response(ser.data)

    # 修改购物车数据
    def put(self, request):

        # 1.获取前端数据
        data = request.data

        # 2.验证
        ser = CartSerializer(data=data)
        # 直接抛出异常用rais_exception = True
        ser.is_valid(raise_exception=True)
        # 线下的时候腰查看异常错误
        # ser.is_valid()
        # print(ser.errors)
        # 获取验证之后的结果
        sku_id = ser.validated_data['sku_id']
        count = ser.validated_data['count']
        selected = ser.validated_data['selected']

        # 判断用户是否登陆
        try:
            user = request.user
        except:
            user = None

        if user is not None:
            # 用户已登陆
            # 1.建立缓存链接
            conn = get_redis_connection('cart')
            # 2.更新hash类型和集合类型
            # hash类型中的累加操作
            conn.hset('cart_%s' %user.id, sku_id, count)
            if selected:
                # 写入一个或多个数据
                conn.sadd('cart_selected_%s' % user.id, sku_id)
            else:
                conn.srem('cart_selected_%s' % user.id, sku_id)
            # 3.返回结果
            return Response(ser.data)
        else:
            # 用户未登陆
            # 1.先判断之前是否登陆过(有cookie)
            cart_cookie = request.COOKIES.get('cart_cookie')
            if cart_cookie:
                # 解密
                cart = pickle.loads(base64.b64decode(cart_cookie))
            else:
                # 2.没有cookie先定义一个空字典
                cart = {}

            cart[sku_id] = {
                'count': count,
                'selected': selected
            }
            # 3.将新的字典加入到cookie
            response = Response(ser.data)
            # 加密处理
            cart_cookie = base64.b64encode(pickle.dumps(cart)).decode()
            response.set_cookie('cart_cookie', cart_cookie, max_age=60*60*24)
            # 4.返回结果
            return Response('ok')

    # 删除购物车数据
    def delete(self, request):

        # 1.获取前端数据
        data = request.data

        # 2.验证
        ser = CartDeleteSerializer(data=data)
        # 直接抛出异常用rais_exception = True
        ser.is_valid(raise_exception=True)
        # 线下的时候腰查看异常错误
        # ser.is_valid()
        # print(ser.errors)
        # 获取验证之后的结果
        sku_id = ser.validated_data['sku_id']

        # 判断用户是否登陆
        try:
            user = request.user
        except:
            user = None

        if user is not None:
            # 用户已登陆
            # 1.建立缓存链接
            conn = get_redis_connection('cart')
            # 2.删除hash类型和集合类型
            # 删除hash类型
            conn.hdel('cart_%s' %user.id, sku_id)
            # 删除一个集合
            conn.srem('cart_selected_%s' % user.id, sku_id)
            # 3.返回结果
            return Response('ok')
        else:
            # 用户未登陆
            # 1.先判断之前是否登陆过(有cookie)
            cart_cookie = request.COOKIES.get('cart_cookie')
            if cart_cookie:
                # 解密
                cart = pickle.loads(base64.b64decode(cart_cookie))

                if sku_id in cart:
                    del cart[sku_id]

                # 4.将新的字典加入到cookie
                response = Response('ok')
                # 加密处理
                cart_cookie = base64.b64encode(pickle.dumps(cart)).decode()
                response.set_cookie('cart_cookie', cart_cookie, max_age=60*60*24)
            # 5.返回结果
            return Response('ok')


class CartSelectionView(APIView):

    # 预防验证用户,因为在post执行之前需要验证用户信息,所以需要跳过验证
    def perform_authentication(self, request):
        pass

    # 全选购物车数据
    def put(self, request):

        # 1.获取前端数据
        data = request.data

        # 2.验证
        ser = CartSelectionSerializer(data=data)
        # 直接抛出异常用rais_exception = True
        ser.is_valid(raise_exception=True)
        # 线下的时候腰查看异常错误
        # ser.is_valid()
        # print(ser.errors)
        # 获取验证之后的结果
        selected = ser.validated_data['selected']

        # 判断用户是否登陆
        try:
            user = request.user
        except:
            user = None

        if user is not None:
            # 用户已登陆
            # 1.建立缓存链接
            conn = get_redis_connection('cart')
            # 2.更新hash类型和集合类型
            # 获取所有的hash的sku_id数据
            sku_id_count = conn.hgetall('cart_%s' % user.id)
            sku_ids = sku_id_count.keys()
            # 更新选中状态
            if selected:
                # 写入一个或多个数据
                # 对列表拆包用一个*对字典拆包用俩个*
                conn.sadd('cart_selected_%s' % user.id, *sku_ids)
            else:
                conn.srem('cart_selected_%s' % user.id, *sku_ids)
            # 3.返回结果
            return Response(ser.data)
        else:
            # 用户未登陆
            # 1.先判断之前是否登陆过(有cookie)
            response = Response(ser.data)
            cart_cookie = request.COOKIES.get('cart_cookie')
            if cart_cookie:
                # 解密
                cart = pickle.loads(base64.b64decode(cart_cookie))

                # 更新字典当中所有的选中状态
                for sku_id, data_dict in cart.items():
                    data_dict['selected'] = selected

                # 加密处理
                cart_cookie = base64.b64encode(pickle.dumps(cart)).decode()
                response.set_cookie('cart_cookie', cart_cookie, max_age=60*60*24)
            # 4.返回结果
            return response
